import 'package:flutter/material.dart';
import 'dart:math';

class KLineChartPage extends StatefulWidget {
  const KLineChartPage({super.key});

  @override
  _KLineChartPageState createState() => _KLineChartPageState();
}

class _KLineChartPageState extends State<KLineChartPage> {
  List<KLineData> kLineData = generateRandomData(30);
  double offsetX = -5 * 15;
  double scale = 1.0;
  String timeFrame = "日";

  static List<KLineData> generateRandomData(int count) {
    Random random = Random();
    List<KLineData> data = [];
    double lastClose = 100.0;
    DateTime time = DateTime.now().subtract(Duration(days: count));

    for (int i = 0; i < count; i++) {
      double open = lastClose;
      double close =
          open + random.nextDouble() * 10 * (random.nextBool() ? 1 : -1);
      double high = max(open, close) + random.nextDouble() * 5;
      double low = min(open, close) - random.nextDouble() * 5;
      print("time:$time");
      data.add(KLineData(
          time: time, open: open, close: close, high: high, low: low));
      lastClose = close;
      time = time.add(const Duration(days: 1));
    }

    return data;
  }

  void changeTimeFrame(String newFrame) {
    setState(() {
      timeFrame = newFrame;
      kLineData = generateRandomData(30);
      offsetX = 0.0;
    });
  }

  void loadMoreData() {
    // 获取当前显示的最早时间
    DateTime latestTime = kLineData.first.time;
    print("latestTime:$latestTime");

    // 假设 fetchHistoryData 根据时间戳来获取历史数据
    List<KLineData> newData = fetchHistoryData(latestTime);

    setState(() {
      // 将新数据添加到现有数据的末尾
      //kLineData.addAll(newData);
      kLineData.insertAll(0, newData); // 插入到数组的前面，保证时间顺序
    });
  }

  List<KLineData> fetchHistoryData(DateTime earliestTime) {
    // 模拟通过时间戳来获取历史数据
    Random random = Random();
    List<KLineData> data = [];
    double lastClose = 100.0;

    // 假设每次加载10条数据，每条数据往前推一天
    DateTime time =
        earliestTime.subtract(const Duration(days: 0)); // 从现有最早时间开始加载数据
    print("time:$time");

    for (int i = 1; i < 10; i++) {
      double open = lastClose;
      double close =
          open + random.nextDouble() * 10 * (random.nextBool() ? 1 : -1);
      double high = max(open, close) + random.nextDouble() * 5;
      double low = min(open, close) - random.nextDouble() * 5;
      // data.add(KLineData(
      //     time: time, open: open, close: close, high: high, low: low));
      data.insert(
          0,
          KLineData(
              time: time, open: open, close: close, high: high, low: low));
      lastClose = close;
      time = time.subtract(const Duration(days: 1)); // 向前推一天
    }

    return data;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("K 线图"),
        actions: [
          DropdownButton<String>(
            value: timeFrame,
            items: ["分", "时", "日", "月", "年"].map((String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Text(value),
              );
            }).toList(),
            onChanged: (value) {
              if (value != null) {
                changeTimeFrame(value);
              }
            },
          ),
        ],
      ),
      body: GestureDetector(
        onHorizontalDragUpdate: (details) {
          //向右拖动时，primaryDelta 为正；向左拖动时，primaryDelta 为负。
          setState(() {
            offsetX += details.primaryDelta ?? 0;
          });

          //print("offsetX:$offsetX");
          // 向右拖动时加载历史数据
          if (offsetX > 50) {
            // 当拖动超过50像素时加载历史数据
            loadMoreData();
            offsetX = 0; // 重置偏移量
          }
        },
        onScaleUpdate: (details) {
          setState(() {
            scale = details.scale.clamp(0.5, 2.0);
          });
        },
        //使用 RepaintBoundary 来减少不必要的重绘
        child: RepaintBoundary(
            child: CustomPaint(
          size: const Size(double.infinity, 400),
          painter: KLinePainter(kLineData, offsetX, scale),
        )),
      ),
    );
  }
}

class KLinePainter extends CustomPainter {
  final List<KLineData> data;
  final double offsetX;
  final double scale;

  KLinePainter(this.data, this.offsetX, this.scale);

  @override
  void paint(Canvas canvas, Size size) {
    Paint gridPaint = Paint()
      ..color = Colors.grey.withOpacity(0.5)
      ..strokeWidth = 0.5;

    double rowHeight = size.height / 5;
    //double columnWidth = size.width / data.length;
    double maxPrice = data.map((e) => e.high).reduce(max);
    double minPrice = data.map((e) => e.low).reduce(min);
    double priceStep = (maxPrice - minPrice) / 5;

    TextPainter textPainter = TextPainter(
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );

    // 绘制水平网格线和价格标签
    for (int i = 0; i < 5; i++) {
      double priceLevel = size.height - (i * rowHeight);
      canvas.drawLine(
          Offset(0, priceLevel), Offset(size.width, priceLevel), gridPaint);

      textPainter.text = TextSpan(
        text: (minPrice + i * priceStep).toStringAsFixed(2),
        style: const TextStyle(color: Colors.black, fontSize: 10),
      );
      textPainter.layout();
      textPainter.paint(canvas, Offset(0, priceLevel - 10));
    }

    // 计算蜡烛图的宽度和间距
    double candleWidth = 10 * scale;
    double space = 5 * scale;
    double startX = offsetX;

    // 绘制垂直网格线和时间标签
    for (int i = 0; i < data.length; i++) {
      // 每隔两个数据点绘制一次
      if (i % 4 == 0) {
        // 计算蜡烛图的中心位置
        double timeX = startX + candleWidth / 2;
        canvas.drawLine(
            Offset(timeX, 0), Offset(timeX, size.height), gridPaint);

        textPainter.text = TextSpan(
          text: "${data[i].time.month}/${data[i].time.day}",
          style: const TextStyle(color: Colors.black, fontSize: 10),
        );
        textPainter.layout();
        textPainter.paint(canvas, Offset(timeX - 10, size.height - 20));
      }
      // 更新 startX 为下一个蜡烛图的起始位置
      startX += candleWidth + space;
    }

    // 重置 startX 为初始值
    startX = offsetX;

    // 绘制蜡烛图
    Paint linePaint = Paint()
      ..color = Colors.black
      ..strokeWidth = 1.0;

    for (var item in data) {
      double highY = size.height -
          (item.high - minPrice) / (maxPrice - minPrice) * size.height;
      double lowY = size.height -
          (item.low - minPrice) / (maxPrice - minPrice) * size.height;
      double openY = size.height -
          (item.open - minPrice) / (maxPrice - minPrice) * size.height;
      double closeY = size.height -
          (item.close - minPrice) / (maxPrice - minPrice) * size.height;

      Paint candlePaint = Paint()
        ..color = item.close >= item.open ? Colors.green : Colors.red
        ..style = PaintingStyle.fill;
      linePaint = Paint()
        ..color = item.close >= item.open ? Colors.green : Colors.red
        ..strokeWidth = 1.0;
      // 绘制蜡烛图的上下影线
      canvas.drawLine(Offset(startX + candleWidth / 2, highY),
          Offset(startX + candleWidth / 2, lowY), linePaint);

      // 绘制蜡烛图的实体部分
      canvas.drawRect(
          Rect.fromLTRB(startX, openY, startX + candleWidth, closeY),
          candlePaint);

      // 更新 startX 为下一个蜡烛图的起始位置
      startX += candleWidth + space;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

class KLineData {
  final DateTime time;
  final double open;
  final double close;
  final double high;
  final double low;

  KLineData(
      {required this.time,
      required this.open,
      required this.close,
      required this.high,
      required this.low});
}
